/***********************************************************************************************************************
/*
/*    single_instance.cpp
/*
/*    This code ensures that only one instance of this program is running.  It's adapted from an article by 
/*    Joseph M. Newcomer at http://www.codeproject.com/cpp/avoidmultinstance.asp
/*
/*    INSTRUCTIONS:
/*
/*	  1.  Make a uuid with uuidgen.exe in the bin directory of the SDK.
/*
/*	  2.  Paste the uuid into the RegisterWindowMessage call below.
/*
/*	  3.  Paste the uuid into the mutex definition below.
/*
/*	  4.  Handle uWM_ARE_YOU_ME in the main window proc.  We return
/*		  the same uWM_ARE_YOU_ME.
/*
/**********************************************************************************************************************/

#include "stdafx.h"


//======================================================================================================================
// DATA
//======================================================================================================================

// GUID obtained for CamTool Feb. 4, 2010
unsigned uWM_ARE_YOU_ME = ::RegisterWindowMessage ( L"CamTool{4D400DC9-FD66-4C42-9A28-D690154B6D4C}");


//======================================================================================================================
//  PROTOTYPES
//======================================================================================================================

static BOOL CALLBACK callback ( HWND hWnd, LPARAM lParam );


//======================================================================================================================
//  CODE
//======================================================================================================================

//----------------------------------------------------------------------------------------------------------------------
//  CALLBACK
//----------------------------------------------------------------------------------------------------------------------
BOOL CALLBACK callback ( HWND hWnd, LPARAM lParam )
{
    DWORD_PTR result;
    LRESULT ok = ::SendMessageTimeout ( hWnd,
                                        uWM_ARE_YOU_ME,
                                        0, 0, 
                                        SMTO_BLOCK | SMTO_ABORTIFHUNG,
                                        200,
                                        &result);
    if ( 0 == ok )
		return TRUE; // ignore this and continue

    if ( result == uWM_ARE_YOU_ME )  
    {
        HWND * target = (HWND *)lParam;  // found it
        *target = hWnd;
        return FALSE;                    // stop search
    }

    return TRUE; // continue search
} 


//----------------------------------------------------------------------------------------------------------------------
// PREVIOUS INSTANCE IS RUNNING
//----------------------------------------------------------------------------------------------------------------------
bool previous_instance_is_running ()
{
    bool bAlreadyRunning;

    HANDLE hMutexOneInstance = ::CreateMutex ( NULL, FALSE, L"CamTool{4D400DC9-FD66-4C42-9A28-D690154B6D4C}" );

	UNREFERENCED_PARAMETER ( hMutexOneInstance );

          // what changes for the alternative solutions
          // is the UID in the above call
          // which will be replaced by a call on
          // createExclusionName

    bAlreadyRunning = ( ::GetLastError() == ERROR_ALREADY_EXISTS || 
                        ::GetLastError() == ERROR_ACCESS_DENIED);

    // The call fails with ERROR_ACCESS_DENIED if the Mutex was 
    // created in a different users session because of passing
    // NULL for the SECURITY_ATTRIBUTES on Mutex creation);

    if ( bAlreadyRunning )
    { 
	    HWND hOther = NULL;
        EnumWindows ( callback, (LPARAM) &hOther );

        if ( hOther != NULL )
        { 
			// previous instance is running so make it
			// visible and bring to foreground

			ShowWindow ( hOther, SW_RESTORE );
			ShowWindow ( hOther, SW_NORMAL );
			SetForegroundWindow ( hOther );		
        } 

        return true;
    } 

    return false;
} 

